package com.example.mq.mqserver.core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

@Data
public class MSGQueue {
    private String name;
    private boolean durable;

    //  拓展功能
    //  是否被独占（只能由一个消费者订阅）
    private boolean exclusive;
    //  自动删除
    private boolean autoDelete;
    //  arguments 表示创建队列时指定的一些额外的参数选项，通过不同的参数，实现不同的功能
    private Map<String,Object> arguments = new HashMap<>();


    public MSGQueue(String name, boolean durable, boolean exclusive, boolean autoDelete) {
        this.name = name;
        this.durable = durable;
        this.exclusive = exclusive;
        this.autoDelete = autoDelete;
    }

    //  存放订阅该队列的消费者
    private final ArrayList<Consumer> consumers = new ArrayList<>();
    //  引入一个原子类作为下标，实现轮询消费者，可以保证线程安全
    private AtomicInteger index = new AtomicInteger(0);

    //  添加一个消费者
    public synchronized void addConsumer(Consumer consumer) {
        consumers.add(consumer);
    }
    //  删除消费者
    public synchronized void removeConsumer(Consumer consumer) {
        for(Consumer toDelete : consumers) {
            if(consumer == toDelete) {
                consumers.remove(consumer);
            }
        }
    }
    //  使用轮询，选出一个消费者
    public synchronized Consumer chooseConsumer() {
        if(consumers.size() == 0) {
            return null;
        }

        int curIndex = index.getAndIncrement() % consumers.size();
        return consumers.get(curIndex);
    }



    //  把 map 存入数据库时，要重写 map 的 getter，setter 方法（序列化对象）
    public String getArguments() {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(arguments);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    public void setArguments(String argumentsJson) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            this.arguments = objectMapper.readValue(argumentsJson,
                    new TypeReference<HashMap<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    //  方便测试，再写一组getter，setter
    public Object getArguments(String key) {
        return arguments.get(key);
    }
    public void setArguments(Map<String,Object> arguments) {
        this.arguments = arguments;
    }
    public void setArguments(String key,String value) {
        arguments.put(key,value);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MSGQueue queue = (MSGQueue) o;
        return durable == queue.durable && exclusive == queue.exclusive && autoDelete == queue.autoDelete && Objects.equals(name, queue.name) && Objects.equals(arguments, queue.arguments) && Objects.equals(consumers, queue.consumers);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, durable, exclusive, autoDelete, arguments, consumers);
    }
}
